﻿using System;
using System.Timers;
using System.Collections.Generic;

namespace ChessBoard
{
    class ChessBoard
    {
        static Board chessBoard = new Board();
        static MoveEntry moveEntry = new MoveEntry();
        static ChessList movesListFrame = new ChessList();
        static ChessClock chessClock = new ChessClock(2, 0, 0);
        static Timer chessTimer = new Timer();
        static bool isWhiteTurn = true;
        static bool SpecialMove = false;
        static List<string> movesList = new List<string>();
        static MoveCoordinates lastMove = new MoveCoordinates();
        static MoveCoordinates nextMove = new MoveCoordinates();

        static void Main()
        {
            IntializeWindow();

            DrawInitialScreen();

            MainLoop();

            Console.ResetColor();
        }

        private static void MainLoop()
        {
            Console.CursorVisible = false;
            
            string input;

            ActivateTimer();

            while (true)
            {
                input = Console.ReadLine();
                int inputLen = input.Length;
                input = input.Trim().ToUpper();

                if (IsValidMove(input))
                {
                    ChangePlayersTurn();

                    movesList.Add(input);

                    //System.Threading.Thread.Sleep(1500);

                    MakeMove();
                }

                UpdateScreen(inputLen);
            }
        }

        private static void UpdateScreen(int inputLen)
        {
            chessTimer.Stop();
            if (inputLen <= 8)
            {
                movesListFrame.UpdateList(movesList);
                moveEntry.Draw();
            }
            else
            {
                DrawInitialScreen();
            }
            chessTimer.Start();
        }

        private static void MakeMove()
        {
            // Checks if the last move is not a caslte: "0-0" or 0-0-0
            if (movesList[movesList.Count - 1][0] != '0' && movesList[movesList.Count - 1][0] != 'O')
            {
                DeleteLastMoveFrame();
                nextMove = LoadMoveCoordinates(movesList[movesList.Count - 1]);
                chessBoard.MovePiece(nextMove);
                chessBoard.DrawMoveFrame(nextMove);
            }
            else
            {
                DeleteLastMoveFrame();
                MakeCastle();
            }
        }

        private static void MakeCastle()
        {
            // Checks for players turn
            if ((movesList.Count - 1) % 2 == 0)
            {
                // Short castle
                if (movesList[movesList.Count - 1] == "0-0" || movesList[movesList.Count - 1] == "O-O")
                {
                    // Loading the Rook move coordinates and moving it
                    // Moving the rook first and then the King
                    nextMove = LoadMoveCoordinates("H1-F1");
                    chessBoard.MovePiece(nextMove);

                    nextMove = LoadMoveCoordinates("E1-G1");
                }
                else // Long castle
                {
                    nextMove = LoadMoveCoordinates("A1-D1");
                    chessBoard.MovePiece(nextMove);

                    nextMove = LoadMoveCoordinates("E1-C1");
                }
            }
            else
            {
                // Short castle
                if (movesList[movesList.Count - 1] == "0-0" || movesList[movesList.Count - 1] == "O-O")
                {
                    // Loading the Rook move coordinates and moving it
                    // Moving the rook first and then the King
                    nextMove = LoadMoveCoordinates("H8-F8");
                    chessBoard.MovePiece(nextMove);

                    nextMove = LoadMoveCoordinates("E8-G8");
                }
                else // Long castle
                {
                    nextMove = LoadMoveCoordinates("A8-D8");
                    chessBoard.MovePiece(nextMove);

                    nextMove = LoadMoveCoordinates("E8-C8");
                }
            }
            
            chessBoard.MovePiece(nextMove);
            chessBoard.DrawMoveFrame(nextMove);
        }

        private static void DeleteLastMoveFrame()
        {
            // The last move frame is deleted if there are at least two moves done
            if (movesList.Count > 1)
            {
                // Checks is the last move is a castle
                if (movesList[movesList.Count - 2][0] != '0' && movesList[movesList.Count - 2][0] != 'O')
                {
                    lastMove = LoadMoveCoordinates(movesList[movesList.Count - 2]);
                    chessBoard.DeleteLastMoveFrame(lastMove);
                }
                // The last move is castle and needs special processing
                else
                {
                    // Checks for players turn
                    if ((movesList.Count - 2) % 2 == 0)
                    {
                        // Short castle
                        if (movesList[movesList.Count - 2] == "0-0" || movesList[movesList.Count - 2] == "O-O")
                        {
                            // Loading the King move coordinates and deleting the last move frame
                            lastMove = LoadMoveCoordinates("E1-G1");
                            chessBoard.DeleteLastMoveFrame(lastMove);
                        }
                        else // Long castle
                        {
                            lastMove = LoadMoveCoordinates("E1-C1");
                            chessBoard.DeleteLastMoveFrame(lastMove);
                        }
                    }
                    else
                    {
                        // Short castle
                        if (movesList[movesList.Count - 2] == "0-0" || movesList[movesList.Count - 2] == "O-O")
                        {
                            // Loading the King move coordinates and deleting the last move frame
                            lastMove = LoadMoveCoordinates("E8-G8");
                            chessBoard.DeleteLastMoveFrame(lastMove);
                        }
                        else // Long castle
                        {
                            lastMove = LoadMoveCoordinates("E8-C8");
                            chessBoard.DeleteLastMoveFrame(lastMove);
                        }
                    }
                }
            }
        }

        private static MoveCoordinates LoadMoveCoordinates(string move)
        {
            return new MoveCoordinates()
            {
                StartRow = '8' - move[1],
                StartCol = move[0] - 'A',
                EndRow = '8' - move[4],
                EndCol = move[3] - 'A'
            };
        }

        private static void ActivateTimer()
        {
            chessTimer.Interval = 1000;
            chessTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
            chessTimer.Start();
        }

        private static void ChangePlayersTurn()
        {
            if (isWhiteTurn)
            {
                isWhiteTurn = false;
            }
            else
            {
                isWhiteTurn = true;
            }
        }

        private static void DrawInitialScreen()
        {
            chessBoard.Draw();
            chessClock.Draw();
            movesListFrame.Draw(movesList);
            moveEntry.Draw();
        }

        private static void IntializeWindow()
        {
            const int windowWidth = 127;
            const int windowHeight = 64;
            int maxMindowWidth = Console.LargestWindowWidth;
            int maxMindowHeight = Console.LargestWindowHeight;

            Console.SetWindowPosition(0, 0);

            if (maxMindowWidth < windowWidth)
            {
                Console.WindowWidth = maxMindowWidth;
            }
            else
            {
                Console.WindowWidth = windowWidth;
            }

            if (maxMindowHeight < windowHeight)
            {
                Console.WindowHeight = maxMindowHeight;
            }
            else
            {
                Console.WindowHeight = windowHeight;
            }

            Console.SetBufferSize(windowWidth, windowHeight);
            Console.Title = "Zorro Chessboard";
        }

        private static void OnTimedEvent(object source, ElapsedEventArgs e)
        {
            if (isWhiteTurn)
            {
                CalculateTime(Player.White);
                chessClock.UpdateClock(Player.White);
            }
            else
            {
                CalculateTime(Player.Black);
                chessClock.UpdateClock(Player.Black);
            }
        }

        private static void CalculateTime(Player player)
        {
            int hours;
            int minutes;
            int seconds;

            if (player == Player.White)
            {
                hours = chessClock.WhiteTime.Hours;
                minutes = chessClock.WhiteTime.Minutes;
                seconds = chessClock.WhiteTime.Seconds;
            }
            else
            {
                hours = chessClock.BlackTime.Hours;
                minutes = chessClock.BlackTime.Minutes;
                seconds = chessClock.BlackTime.Seconds;
            }

            if (seconds > 0)
            {
                seconds--;
            }
            else
            {
                seconds = 59;
                if (minutes > 0)
                {
                    minutes--;
                }
                else
                {
                    minutes = 59;
                    hours--;
                }
            }

            if (player == Player.White)
            {
                chessClock.WhiteTime = new PlayerTime()
                {
                    Hours = hours,
                    Minutes = minutes,
                    Seconds = seconds
                };
            }
            else
            {
                chessClock.BlackTime = new PlayerTime()
                {
                    Hours = hours,
                    Minutes = minutes,
                    Seconds = seconds
                };
            }
        }

        private static bool IsValidMove(string input)
        {
            // input = "e2-e4" or "0-0"or "0-0-0"
            if (input == "0-0" || input == "0-0-0" || input == "O-O" || input == "O-O-O")
            {
                SpecialMove = true;
                // Special move validation
            }
            else
            {
                if (!IsValidFormat(input)) return false;
                if (IsSquareEmpty(input)) return false;
                if (!PlayersTurn(input)) return false;
                if (!IsNextSquareAvailable(input)) return false;
                if (!IsValidPieceMovement(input)) return false;
                if (IsMoveDiscoveringCheck(input)) return false;
            }
            return true;
        }

        private static bool IsMoveDiscoveringCheck(string input)
        {
            return false;
        }

        private static bool IsValidPieceMovement(string input)
        {
            return true;
        }

        private static bool IsNextSquareAvailable(string input)
        {
            if ((isWhiteTurn && chessBoard.SquareMatrix['8' - input[4], input[3] - 'A'].PColor == PieceColor.White)
                || (isWhiteTurn == false && chessBoard.SquareMatrix['8' - input[4], input[3] - 'A'].PColor == PieceColor.Black)) return false;
            return true;
        }

        private static bool IsSquareEmpty(string input)
        {
            if (chessBoard.SquareMatrix['8' - input[1], input[0] - 'A'].PType == PieceType.None) return true;
            return false;
        }

        private static bool PlayersTurn(string input)
        {
            if ((isWhiteTurn && chessBoard.SquareMatrix['8' - input[1], input[0] - 'A'].PColor == PieceColor.Black)
                || (isWhiteTurn == false && chessBoard.SquareMatrix['8' - input[1], input[0] - 'A'].PColor == PieceColor.White)) return false;
            return true;
        }

        private static bool IsValidFormat(string input)
        {
            if (input == String.Empty)
            {
                return false;
            }
            if ((input[0] - 'A') < 0 || (input[0] - 'A' > 7)
                || (input[3] - 'A') < 0 || (input[3] - 'A' > 7))
            {
                return false;
            }
            if (('8' - input[1]) < 0 || ('8' - input[1]) > 7
                || ('8' - input[4]) < 0 || ('8' - input[4]) > 7)
            {
                return false;
            }
            return true;
        }
    }
}